package com.sharing.util;

import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerHandlerImpl;
import lombok.Data;
import lombok.extern.java.Log;
import org.apache.ibatis.javassist.bytecode.stackmap.BasicBlock;
import org.springframework.stereotype.Component;

import java.awt.geom.QuadCurve2D;
import java.security.PublicKey;

/**
 * @author MingTian
 * @version 1.0
 * @description TODO 基于漏斗算法实现的对请求限流的限制器
 * @date 2023/7/18 15:08
 */
@Data
public class FunnelRateLimiter {
    /**
     * 漏斗总容量，即漏斗最多容纳的请求数量
     */
    private int capacity;

    /**
     * 请求流水速度，
     * 系统允许该行为的最大频率
     */
    private float leakingRate;

    /**
     * 漏斗剩余空间，
     * 当前行为可持续进行的数量
     */
    private int leftQuota;

    /**
     * 上次漏水时间
     */
    private long leakingTs;

    /**
     * 限制器的构造方法
     * @param capacity
     * @param leakingRate
     */
    public FunnelRateLimiter(int capacity, float leakingRate) {
        this.capacity = capacity;
        this.leakingRate = leakingRate;
        this.leftQuota = capacity;
        this.leakingTs = System.currentTimeMillis();
    }

    public void makeSpace() {
        long nowTs = System.currentTimeMillis();
        long deltaTs = nowTs - leakingTs;
        int deltaQuota = (int) (deltaTs * leakingRate);

        // 间隔时间太长，整数数字过大溢出
        if (deltaQuota < 0) {
            this.leftQuota = capacity;
            this.leakingTs = nowTs;
            return;
        }

        // 腾出时间太小，最小单位为1
        if (deltaQuota < 1) {
            return;
        }

        this.leftQuota += deltaQuota;
        this.leakingTs = nowTs;
        if (this.leftQuota > this.capacity) {
            this.leftQuota = this.capacity;
        }
    }

    public boolean watering(int quota) {
        makeSpace();
        if (this.leftQuota >= quota) {
            this.leftQuota -= quota;
            return true;
        }
        return false;
    }
}
